package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
)

/*
这个包可以实现json的编码和解码，就是将json字符串转换为struct，或者将struct转换为json。
核心的两个函数
func Marshal(v interface{}) ([]byte, error)
将struct编码成json，可以接收任意类型
func Unmarshal(data []byte, v interface{}) error
将json转码为struct结构体
两个核心结构体

	type Decoder struct {
		// contains filtered or unexported fields
	}

从输入流读取并解析json

	type Encoder struct {
		// contains filtered or unexported fields
	}

写json到输出流
*/

// 实例演示:结构体转换为json
type Perqson struct {
	Name  string
	Age   int
	Email string
}

func Marshal() {
	p := Perqson{
		Name:  "tom",
		Age:   20,
		Email: "tom@gmail.com",
	}
	b, _ := json.Marshal(p)          //([]byte, error)
	fmt.Printf("b: %v\n", string(b)) //{"Name":"tom","Age":20,"Email":"tom@gmail.com"}
}

// json转换为结构体
func Unmarshal() {
	b1 := []byte(`{"Name":"tom","Age":20,"Email":"tom@gmail.com"}`)
	var m Perqson
	json.Unmarshal(b1, &m)
	fmt.Printf("m: %v\n", m) //m: {tom 20 tom@gmail.com}
}

// 解析嵌套类型
func testo3() {
	b := []byte(`{"Name":"tom","Age":20,"Email":"tom@gmail.com","Parents":["big tom","kite"]}`)
	var f interface{}
	json.Unmarshal(b, &f)
	fmt.Printf("f: %v\n", f) //f: map[Age:20 Email:tom@gmail.com Name:tom Parents:[big tom kite]]
}

// 解析嵌套引用类型
func testo4() {
	type Person struct {
		Name   string
		Age    int
		Email  string
		Parent []string
	}

	p := Person{
		Name:   "tom",
		Age:    20,
		Email:  "tom@gmail.com",
		Parent: []string{"big tom", "big kite"},
	}

	b, _ := json.Marshal(p)
	fmt.Printf("b: %v\n", string(b)) //b: {"Name":"tom","Age":20,"Email":"tom@gmail.com","Parent":["big tom","big kite"]}
}

// io流Reader Writer可以扩展到http websocket等场景
func testo5() {
	// dec := json.NewDecoder(os.Stdin)
	// a.json : {"Name":"tom","Age":20,"Email":"tom@gmail.com","Parents":["tom","kite"]}
	f, _ := os.Open("a.json")
	dec := json.NewDecoder(f)
	enc := json.NewEncoder(os.Stdout)
	for {
		var v map[string]interface{}
		if err := dec.Decode(&v); err != nil {
			log.Println(err)
			return
		}
		fmt.Printf("v: %v\n", v)
		if err := enc.Encode(&v); err != nil {
			log.Println(err)
		}

	}
}

func main() {
	Marshal()
	Unmarshal()
	testo3()
	testo4()
	testo5()
}
